package com.jiubanqingchen.wish.framework.security;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.redis.Cache;
import com.jiubanqingchen.wish.framework.consts.BaseKey;
import com.jiubanqingchen.wish.framework.consts.CacheKey;
import com.jiubanqingchen.wish.kit.BlankKit;
import com.jiubanqingchen.wish.model.models.Dept;
import com.jiubanqingchen.wish.model.models.Role;
import com.jiubanqingchen.wish.model.models.base.BaseDept;
import com.jiubanqingchen.wish.plugin.cache.redis.annotation.Cacheable;
import com.jiubanqingchen.wish.plugin.cache.redis.kit.CacheKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 安全服务
 *
 * @author light_dust
 * @since 2021/1/4 8:53
 */
public class AuthService {

    private final static Logger logger = LoggerFactory.getLogger(AuthService.class);

    private final static String findUserDeptSql = "org_auth.findUserDept";

    private final static String findUserRoleSql = "org_auth.findUserRole";

    private final static String findRoleResourceSql = "org_auth.findRoleResource";

    private final static String findRoleAuthoritySql = "org_auth.findRoleAuthority";

    /**
     * 查询用户的部门信息
     *
     * @param userId 用户id
     */
    @Cacheable(key = CacheKey.USER_DEPT)
    public List<Dept> getUserDept(String userId) {
        return Dept.dao.find(Db.getSql(findUserDeptSql), userId);
    }

    /**
     * 查询用户的主要部门 用户为多部门模式 并有且只有一个主要部门 当用户只有一个部门的时候,此部门为主要部门
     *
     * @param userId 用户id
     */
    public Dept getUserMainDept(String userId) {
        List<Dept> deptList = getUserDept(userId);
        if (BlankKit.isBlankList(deptList)) return null;
        List<Dept> deptFilterList = deptList.stream().filter(BaseDept::getValid).collect(Collectors.toList());
        return BlankKit.isBlankList(deptFilterList) ? null : deptFilterList.get(0);
    }

    /**
     * 查询用户的角色信息
     *
     * @param userId 用户id
     */
    @Cacheable(key = CacheKey.USER_ROLE)
    public List<Role> getUserRole(String userId) {
        return Role.dao.find(Db.getSql(findUserRoleSql), userId, userId);
    }

    /**
     * 获取角色可使用菜单权限
     *
     * @param roleId 角色id
     */
    @Cacheable(key = CacheKey.ROLE_USE_MENU_RESOURCE)
    public List<String> getRoleUseMenuResource(String roleId) {
        return Db.query(Db.getSql(findRoleResourceSql), roleId, BaseKey.RESOURCE_CATEGORY_USE, BaseKey.RESOURCE_TYPE_MENU);
    }

    /**
     * 获取角色可分配菜单权限
     *
     * @param roleId 角色id
     */
    @Cacheable(key = CacheKey.ROLE_ASSIGN_MENU_RESOURCE)
    public List<String> getRoleAssignMenuResource(String roleId) {
        return Db.query(Db.getSql(findRoleResourceSql), roleId, BaseKey.RESOURCE_CATEGORY_ASSIGN, BaseKey.RESOURCE_TYPE_MENU);
    }

    /**
     * 获取角色可使用接口权限
     *
     * @param roleId 角色id
     */
    @Cacheable(key = CacheKey.ROLE_USE_INTERFACE_RESOURCE)
    public List<String> getRoleUseInterfaceResource(String roleId) {
        return Db.query(Db.getSql(findRoleResourceSql), roleId, BaseKey.RESOURCE_CATEGORY_USE, BaseKey.RESOURCE_TYPE_INTERFACE);
    }

    /**
     * 获取角色可分配接口权限
     *
     * @param roleId 角色id
     */
    @Cacheable(key = CacheKey.ROLE_ASSIGN_INTERFACE_RESOURCE)
    public List<String> getRoleAssignInterfaceResource(String roleId) {
        return Db.query(Db.getSql(findRoleResourceSql), roleId, BaseKey.RESOURCE_CATEGORY_ASSIGN, BaseKey.RESOURCE_TYPE_INTERFACE);
    }

    /**
     * 获取角色使用的接口authorityKey
     *
     * @param roleId 角色id
     */
    @Cacheable(key = CacheKey.ROLE_USE_INTERFACE_AUTHORITY)
    public List<String> getRoleUserInterfaceAuthorityKey(String roleId) {
        return Db.query(Db.getSql(findRoleAuthoritySql), roleId, BaseKey.RESOURCE_CATEGORY_USE, BaseKey.RESOURCE_TYPE_INTERFACE);
    }

    /**
     * 获取用户可使用的接口权限 这里不做缓存 因为角色已经有缓存 角色下面的权限也有缓存 当角色权限更改时我们只用清理掉被修改角色的权限缓存就行 java的循环遍历是及其快的
     *
     * @param userId 用户id
     */
    public List<String> getUserUseInterfaceAuthorityKey(String userId) {
        List<Role> roleList = getUserRole(userId);
        if (BlankKit.isBlankList(roleList)) return null;
        List<String> list = new ArrayList<>();
        List<String> child;
        for (Role role : roleList) {
            child = getRoleUserInterfaceAuthorityKey(role.getRoleId());
            if (BlankKit.notBlankList(child)) list.addAll(child);
        }
        //去掉重复的key
        return list.stream().distinct().collect(Collectors.toList());
    }


    /**
     * 校验角色是否有某个权限
     *
     * @param userId       用户id
     * @param authorityKey 权限key
     */
    public boolean judgeAuthority(String userId, String authorityKey) {
        return getUserUseInterfaceAuthorityKey(userId).contains(authorityKey);
    }

    public void deleteUserCache(String userId) {
        Record params = new Record().set("userId", userId);
        CacheKit cacheKit = CacheKit.me();
        Cache cache = cacheKit.getCache();
        cache.del(cacheKit.createCacheKey(CacheKey.USER_DEPT, params));
        cache.del(cacheKit.createCacheKey(CacheKey.USER_ROLE, params));
        logger.info("正在删除用户 [{}] 的部门、角色缓存...", userId);
    }

    /**
     * 删除角色可使用的菜单权限缓存
     *
     * @param roleId 角色id
     */
    public void deleteRoleMenuAuthorityCache(String roleId) {
        Record params = new Record().set("roleId", roleId);
        CacheKit cacheKit = CacheKit.me();
        Cache cache = cacheKit.getCache();
        cache.del(cacheKit.createCacheKey(CacheKey.ROLE_USE_MENU_RESOURCE, params));
        cache.del(cacheKit.createCacheKey(CacheKey.ROLE_ASSIGN_MENU_RESOURCE, params));
        logger.info("正在删除角色 [{}] 菜单的(使用、分配)使用权限缓存...", roleId);
    }

    /**
     * 删除角色可使用的接口权限缓存
     *
     * @param roleId 角色id
     */
    public void deleteRoleInterfaceAuthorityCache(String roleId) {
        Record params = new Record().set("roleId", roleId);
        CacheKit cacheKit = CacheKit.me();
        Cache cache = cacheKit.getCache();
        cache.del(cacheKit.createCacheKey(CacheKey.ROLE_USE_INTERFACE_RESOURCE, params));
        cache.del(cacheKit.createCacheKey(CacheKey.ROLE_USE_INTERFACE_AUTHORITY, params));
        cache.del(cacheKit.createCacheKey(CacheKey.ROLE_ASSIGN_INTERFACE_RESOURCE, params));
        logger.info("正在删除角色 [{}] 接口的(使用、分配)使用权限缓存...", roleId);
    }

    /**
     * 删除角色的所有缓存
     *
     * @param roleId 角色id
     */
    public void deleteRoleCache(String roleId) {
        deleteRoleMenuAuthorityCache(roleId);
        deleteRoleInterfaceAuthorityCache(roleId);
    }
}
